/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.seguradora.model.repository.impl;

import br.com.seguradora.exception.PersistenciaException;
import br.com.seguradora.model.Associado;
import br.com.seguradora.model.Grupo;
import br.com.seguradora.model.Marca;
import br.com.seguradora.model.Modelo;
import br.com.seguradora.model.Veiculo;
import br.com.seguradora.model.constant.EspecieVeiculo;
import br.com.seguradora.model.constant.TipoCombustivel;
import br.com.seguradora.model.constant.TipoVeiculo;
import br.com.seguradora.model.repository.TodosVeiculos;
import br.com.seguradora.persistence.GerenciadorDeConexao;
import br.com.seguradora.view.DisplayFilter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Diego
 */
public class TodosVeiculosImpl implements TodosVeiculos {
    
    private Connection conn;
    private PreparedStatement pr;
    private ResultSet rs;
    
    @Override
    public boolean inserir(Veiculo veiculo) throws PersistenciaException {
        if (veiculo == null) {
            throw new PersistenciaException("Não foi informado o veículo a cadastrar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("INSERT INTO VEICULO(ID, BLOQUEADO, TIPO, RENAVAM, EXERCICIO, NOME_PROPRIETARIO, CPF_PROPRIETARIO, PLACA, CHASSI, ESPECIE, COMBUSTIVEL, ID_MODELO, ANO_FABRICACAO, ANO_MODELO, ESPECIFICACAO, CATEGORIA, COR_PREDOMINANTE, OBSERVACAO, ID_ASSOCIADO, ID_GRUPO, VALOR, COTAS, MENSALIDADE, FRANQUIA, SHADOW) VALUES(NULL, FALSE, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE);",
                    Statement.RETURN_GENERATED_KEYS);
            pr.setString(1, veiculo.getTipo().name());
            pr.setString(2, veiculo.getRenavam());
            pr.setString(3, veiculo.getExercicio());
            pr.setString(4, veiculo.getNomeProprietario());
            pr.setString(5, veiculo.getCpfProprietario());
            pr.setString(6, veiculo.getPlaca());
            pr.setString(7, veiculo.getChassi());
            pr.setString(8, veiculo.getEspecie().name());
            pr.setString(9, veiculo.getCombustivel().name());
            pr.setLong(10, veiculo.getModelo() != null ? veiculo.getModelo().getId() : 0);
            pr.setString(11, veiculo.getAnoFabricacao());
            pr.setString(12, veiculo.getAnoModelo());
            pr.setString(13, veiculo.getEspecificacao());
            pr.setString(14, veiculo.getCategoria());
            pr.setString(15, veiculo.getCorPredominante());
            pr.setString(16, veiculo.getObservacao());
            pr.setLong(17, veiculo.getAssociado() != null ? veiculo.getAssociado().getId() : 0);
            pr.setLong(18, veiculo.getGrupo() != null ? veiculo.getGrupo().getId() : 0);
            pr.setDouble(19, veiculo.getValor());
            pr.setDouble(20, veiculo.getCotas());
            pr.setDouble(21, veiculo.getMensalidade());
            pr.setDouble(22, veiculo.getFranquia());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
                rs = pr.getGeneratedKeys();
                rs.first();
                long id = rs.getLong(1);
                veiculo.setId(id);
                
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível cadastrar o veículo.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return sucesso;
    }
    
    @Override
    public boolean atualizar(Veiculo veiculo) throws PersistenciaException {
        if (veiculo == null) {
            throw new PersistenciaException("Não foi informado o veículo a atualizar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE VEICULO SET BLOQUEADO=?, TIPO=?, RENAVAM=?, EXERCICIO=?, NOME_PROPRIETARIO=?, CPF_PROPRIETARIO=?, PLACA=?, CHASSI=?, ESPECIE=?, COMBUSTIVEL=?, ID_MODELO=?, ANO_FABRICACAO=?, ANO_MODELO=?, ESPECIFICACAO=?, CATEGORIA=?, COR_PREDOMINANTE=?, OBSERVACAO=?, ID_ASSOCIADO=?, ID_GRUPO=?, VALOR=?, COTAS=?, MENSALIDADE=?, FRANQUIA=? WHERE ID=?");
            pr.setBoolean(1, veiculo.isBloqueado());
            pr.setString(2, veiculo.getTipo().name());
            pr.setString(3, veiculo.getRenavam());
            pr.setString(4, veiculo.getExercicio());
            pr.setString(5, veiculo.getNomeProprietario());
            pr.setString(6, veiculo.getCpfProprietario());
            pr.setString(7, veiculo.getPlaca());
            pr.setString(8, veiculo.getChassi());
            pr.setString(9, veiculo.getEspecie().name());
            pr.setString(10, veiculo.getCombustivel().name());
            pr.setLong(11, veiculo.getModelo() != null ? veiculo.getModelo().getId() : 0);
            pr.setString(12, veiculo.getAnoFabricacao());
            pr.setString(13, veiculo.getAnoModelo());
            pr.setString(14, veiculo.getEspecificacao());
            pr.setString(15, veiculo.getCategoria());
            pr.setString(16, veiculo.getCorPredominante());
            pr.setString(17, veiculo.getObservacao());
            pr.setLong(18, veiculo.getAssociado() != null ? veiculo.getAssociado().getId() : 0);
            pr.setLong(19, veiculo.getGrupo() != null ? veiculo.getGrupo().getId() : 0);
            pr.setDouble(20, veiculo.getValor());
            pr.setDouble(21, veiculo.getCotas());
            pr.setDouble(22, veiculo.getMensalidade());
            pr.setDouble(23, veiculo.getFranquia());
            pr.setLong(24, veiculo.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível atualizar o veículo.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }
    
    @Override
    public boolean excluir(Veiculo veiculo) throws PersistenciaException {
        if (veiculo == null) {
            throw new PersistenciaException("Não foi informado o veículo a excluir.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE VEICULO SET SHADOW=TRUE WHERE ID=?;");
            pr.setLong(1, veiculo.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível excluir o veículo.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }
    
    @Override
    public List<Veiculo> listarTodos(int... limits) throws PersistenciaException {
        List<Veiculo> lista = new ArrayList<Veiculo>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE ORDER BY V.ID DESC LIMIT ?, ?");
            pr.setInt(1, limits[0]);
            pr.setInt(2, limits[1]);
            rs = pr.executeQuery();
            while (rs.next()) {
                Veiculo veiculo = this.criarVeiculo(rs);
                lista.add(veiculo);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os veículos recentes.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    @Override
    public List<Veiculo> listarPeloRenavam(String renavam, DisplayFilter displayFilter) throws PersistenciaException {
        List<Veiculo> lista = new ArrayList<Veiculo>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE AND V.RENAVAM=? AND V.BLOQUEADO=? ORDER BY V.ID");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE AND V.RENAVAM=? ORDER BY V.ID");
            }
            pr.setString(1, renavam);
            rs = pr.executeQuery();
            while (rs.next()) {
                Veiculo veiculo = this.criarVeiculo(rs);
                lista.add(veiculo);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os veículos pelo renavam.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    @Override
    public List<Veiculo> listarPeloAssociado(String associado, DisplayFilter displayFilter) throws PersistenciaException {
        List<Veiculo> lista = new ArrayList<Veiculo>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE AND A.NOME LIKE ? AND V.BLOQUEADO=? ORDER BY A.NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE AND A.NOME LIKE ? ORDER BY A.NOME");
            }
            pr.setString(1, "%" + associado + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Veiculo veiculo = this.criarVeiculo(rs);
                lista.add(veiculo);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os veículos pelo associado.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    @Override
    public List<Veiculo> listarPelaPlaca(String placa, DisplayFilter displayFilter) throws PersistenciaException {
        List<Veiculo> lista = new ArrayList<Veiculo>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE AND V.PLACA=? AND V.BLOQUEADO=? ORDER BY V.ID");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT V.ID, V.BLOQUEADO, V.TIPO, V.RENAVAM, V.EXERCICIO, V.NOME_PROPRIETARIO, V.CPF_PROPRIETARIO, V.PLACA, V.CHASSI, V.ESPECIE, V.COMBUSTIVEL, V.ANO_FABRICACAO, V.ANO_MODELO, V.ESPECIFICACAO, V.CATEGORIA, V.COR_PREDOMINANTE, V.OBSERVACAO, V.VALOR, V.COTAS, V.MENSALIDADE, V.FRANQUIA, M.ID AS ID_MODELO, M.NOME AS NOME_MODELO, MA.ID AS ID_MARCA, MA.NOME AS NOME_MARCA, A.ID AS ID_ASSOCIADO, A.NOME AS NOME_ASSOCIADO, G.ID AS ID_GRUPO, G.NOME AS NOME_GRUPO FROM VEICULO V INNER JOIN MODELO M ON V.ID_MODELO = M.ID INNER JOIN MARCA MA ON M.ID_MARCA = MA.ID INNER JOIN ASSOCIADO A ON V.ID_ASSOCIADO = A.ID INNER JOIN GRUPO G ON V.ID_GRUPO = G.ID WHERE V.SHADOW=FALSE AND V.PLACA=? ORDER BY V.ID");
            }
            pr.setString(1, placa);
            rs = pr.executeQuery();
            while (rs.next()) {
                Veiculo veiculo = this.criarVeiculo(rs);
                lista.add(veiculo);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os veículos pela placa.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }
    
    private Veiculo criarVeiculo(ResultSet rs) throws PersistenciaException {
        Veiculo veiculo = null;
        try {
            veiculo = new Veiculo(rs.getLong("ID"));
            veiculo.setBloqueado(rs.getBoolean("BLOQUEADO"));
            veiculo.setTipo(TipoVeiculo.valueOf(rs.getString("TIPO")));
            veiculo.setRenavam(rs.getString("RENAVAM"));
            veiculo.setExercicio(rs.getString("EXERCICIO"));
            veiculo.setNomeProprietario(rs.getString("NOME_PROPRIETARIO"));
            veiculo.setCpfProprietario(rs.getString("CPF_PROPRIETARIO"));
            veiculo.setPlaca(rs.getString("PLACA"));
            veiculo.setChassi(rs.getString("CHASSI"));
            veiculo.setEspecie(EspecieVeiculo.valueOf(rs.getString("ESPECIE")));
            veiculo.setCombustivel(TipoCombustivel.valueOf(rs.getString("COMBUSTIVEL")));
            veiculo.setModelo(new Modelo(rs.getLong("ID_MODELO"), rs.getString("NOME_MODELO"),
                    new Marca(rs.getLong("ID_MARCA"), rs.getString("NOME_MARCA"))));
            veiculo.setAnoFabricacao(rs.getString("ANO_FABRICACAO"));
            veiculo.setAnoModelo(rs.getString("ANO_MODELO"));
            veiculo.setEspecificacao(rs.getString("ESPECIFICACAO"));
            veiculo.setCategoria(rs.getString("CATEGORIA"));
            veiculo.setCorPredominante(rs.getString("COR_PREDOMINANTE"));
            veiculo.setObservacao(rs.getString("OBSERVACAO"));
            veiculo.setAssociado(new Associado(rs.getLong("ID_ASSOCIADO"), rs.getString("NOME_ASSOCIADO")));
            veiculo.setGrupo(new Grupo(rs.getLong("ID_GRUPO"), rs.getString("NOME_GRUPO")));
            veiculo.setValor(rs.getDouble("VALOR"));
            veiculo.setCotas(rs.getDouble("COTAS"));
            veiculo.setMensalidade(rs.getDouble("MENSALIDADE"));
            veiculo.setFranquia(rs.getDouble("FRANQUIA"));
            
        } catch (SQLException sqlex) {
            StringBuilder msg = new StringBuilder("Não foi possível obter os dados do veículo.");
            msg.append("\nMotivo: ").append(sqlex.getMessage());
            throw new PersistenciaException(msg.toString());
        }
        return veiculo;
    }
}
